package main

import (
	"encoding/json"
	"fmt"
	"github.com/gorilla/mux"
	"github.com/justinas/alice"
	"gopkg.in/validator.v2"
	"log"
	"net/http"
)
// App : Env Router Middleware
type App struct {
	Router *mux.Router
	MiddleWares *MiddleWare
	config *Env
}

// shortLink 请求
type shortenReq struct {
	URL string `json:"url" validate:"nonzero"`
	ExpirationInMinutes int64 `json:"expiration_in_minutes" validate:"min=0"`
}

// shortLink 响应
type shortlinkResp struct {
	ShortLink string `json:"shortlink"`
}

// 初始化函数初始化app
func (a *App) Initialize(e *Env)  {
	// 定义log格式
	log.SetFlags(log.LstdFlags | log.Lshortfile)//打印日志发生的时间和日期、日志的文件名

	//初始化Config
	a.config = e

	a.Router = mux.NewRouter()

	// 初始化middleware
	a.MiddleWares = &MiddleWare{}


	a.InitializeRoutes()
}

//绑定路由和handle
func (a *App) InitializeRoutes()  {
	//a.Router.HandleFunc("/api/shorten", a.createShortlink).Methods("POST")
	//a.Router.HandleFunc("/api/info", a.getShortlinkInfo).Methods("GET")
	//a.Router.HandleFunc("/{shortlink:[a-zA-Z0-9]{1,11}}", a.redirect).Methods("GET")

	m := alice.New(a.MiddleWares.LoggingHandler, a.MiddleWares.RecoverHandler)

	a.Router.Handle("/api/shorten", m.ThenFunc(a.createShortlink)).Methods("POST")
	a.Router.Handle("/api/info", m.ThenFunc(a.getShortlinkInfo)).Methods("GET")
	a.Router.Handle("/{shortlink:[a-zA-Z0-9]{1,11}}",  m.ThenFunc(a.redirect)).Methods("GET")
}


// 具体的匹配后执行的函数
func (a *App) createShortlink(w http.ResponseWriter, r *http.Request) {
	var req shortenReq
	if err := json.NewDecoder(r.Body).Decode(&req);err != nil{
		responWithError(w, StatusError{http.StatusBadRequest,
			fmt.Errorf("parse paramters failed %v", r.Body)})
		return
	}
	if err := validator.Validate(req); err != nil {
		responWithError(w, StatusError{http.StatusBadRequest,
			fmt.Errorf("validate paramters failed %v", req)})
		return
	}
	defer r.Body.Close()

	//fmt.Printf("%v\n",req)

	s, err := a.config.S.Shorten(req.URL, req.ExpirationInMinutes)
	if err != nil {
		responWithError(w, err)
	}else{
		respondWithJSON(w, http.StatusCreated, shortlinkResp{ShortLink: s})
	}
}

func (a *App) getShortlinkInfo(w http.ResponseWriter, r *http.Request) {
	vals := r.URL.Query()
	s := vals.Get("shortlink")

	//fmt.Printf("%s\n", s)

	d, err := a.config.S.ShortlinkInfo(s)
	if err != nil {
		responWithError(w, err)
	} else {
		respondWithJSON(w, http.StatusOK, d)
	}
}


func (a *App) redirect(w http.ResponseWriter, r *http.Request) {
	vars := mux.Vars(r)
	//fmt.Printf("%s\n", vars["shortlink"])

	u, err := a.config.S.Unshorten(vars["shortlink"])
	if err != nil {
		 responWithError(w, err)
	} else {
		http.Redirect(w, r, u ,http.StatusTemporaryRedirect)
	}
}


// 启动监听服务器
func (a *App) Run(addr string)  {
	log.Fatal(http.ListenAndServe(addr, a.Router))
}

// 错误处理
func responWithError(w http.ResponseWriter, err error)  {
	switch e := err.(type) {
	case Error://自定义的错误类型
		log.Printf("HTTP %d - %s", e.Status(), e)
		respondWithJSON(w, e.Status(), e.Error())
	default:
		respondWithJSON(w, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError))
	}
}

// 返回json信息
func respondWithJSON(w http.ResponseWriter, code int, payload interface{})  {
	resp, _ := json.Marshal(payload)
	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(code)
	w.Write(resp)
}